﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using logika;

namespace symulacja_ewolucji
{
    public enum SimulationType
    {
        ExisitingTree,
        StartSequence
    }

    public partial class MainForm : Form
    {
        SimulationType _simulationType;
        string _path = "";
        Node _root = null;

        public MainForm()
        {
            InitializeComponent();
            simulationTypeComboBox.SelectedIndex = 1;
            var args = Environment.GetCommandLineArgs();
            if (args.Length > 0)
            {
                _path = args[1];
                SetPathLabel();
            }
        }

        /// <summary>
        /// Generuje drzewo gatunków wg rozkładu wykładniczego w podanym przedziale czasy
        /// </summary>
        /// <param name="max_czas">Czas rozwijania się drzewka</param>
        private void generuj_drzewko(int max_czas)
        {
            List<Node> liscie = new List<Node>();
            _root = new Node("");
            liscie.Add(_root);

            while (liscie.Count > 0)
            {
                int c = liscie.Count;
                for (int j = 0; j < c; j++)
                {
                    var gatunek = liscie[j];
                    gatunek.wiek += Kimura.losuj_czas_gatunku();                    
                    if (gatunek.wiek < max_czas)
                    {
                        gatunek.rozdziel();
                        liscie.AddRange(gatunek.potomne);
                    }
					else gatunek.wiek = max_czas;
                }
                while (c-- > 0) liscie.RemoveAt(0);
            }
            liscie.Clear();
        }

        /// <summary>
        /// przeprowadza ewolucję w istniejącym drzewku wg modulu Kimury
        /// </summary>
        /// <param name="kimura"></param>
        /// <param name="gatunek"></param>
        private void przeprowadz_symulacje(Kimura kimura, Node gatunek, int wiek_rodzica = 0)
        {
            if (gatunek == null) return;
            gatunek.sekwencja = kimura.ewoluuj(gatunek.sekwencja, gatunek.wiek - wiek_rodzica);
            foreach (var child in gatunek.potomne)
            {
                child.sekwencja = gatunek.sekwencja;
                przeprowadz_symulacje(kimura, child, gatunek.wiek);
            }
        }

        /// <summary>
        /// Przeprowadza symulację na podstawie podanych parametrów.
        /// </summary>
        private void simulateButton_Click(object sender, EventArgs e)
        {
            try
            {
                var kimura = new Kimura(Double.Parse(alfaTextBox.Text), Double.Parse(betaTextBox.Text), Double.Parse(sredniaTextBox.Text) * 1000);
                if (_simulationType == SimulationType.StartSequence)
                {
                    generuj_drzewko(Int32.Parse(timeTextBox.Text) * 1000);
                    _root.sekwencja = GetDnaString();
                    przeprowadz_symulacje(kimura, _root);
					zapiszStruktureButton.Enabled = true;
                }
                else
                {
                    // Wczytane drzewo ważone będzie pewnie w odgórnie ustalonym formacie.
                    // Procedura działania będzie inna?
					if (_root == null) throw new Exception("Wpierw wczytaj strukturę!");
                    _root.sekwencja = GetDnaString();
                    przeprowadz_symulacje(kimura, _root);
                }

                showTreeButton.Enabled = true;
            }
            catch (Exception ex)
            {
                //TODO: dokładniejszy opis błędu
                MessageBox.Show("Symulacja nie może zostać przeprowadzona. Sprawdź, czy podane parametry są poprawne.",
                    "Błąd", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private string GetDnaString()
        {
            if (!File.Exists(_path))
                throw new FileNotFoundException();
            string dna;
            using (var reader = new StreamReader(_path))
            {
                dna = reader.ReadToEnd();
            }
            return dna;
        }

        /// <summary>
        /// Pokazuje uzyskane drzewo, prawdopodobnie z wykorzystaniem TreeView.
        /// </summary>
        private void showTreeButton_Click(object sender, EventArgs e)
        {
           /* if (_root == null) return;
            if (File.Exists("drzewko.phy")) File.Delete("drzewko.phy");
            System.IO.StreamWriter plik = new System.IO.StreamWriter("drzewko.phy");
            plik.WriteLine(_root.drukuj_liscie() + ";");
            plik.Close();
            */

            WriterReader zapisz = new WriterReader();
            int ilosc_drzewek = zapisz.Save(_root, "drzewko");
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(@"C:\Program Files (x86)\TreeView\treev32.exe");
            string paramsy = "drzewko" + (ilosc_drzewek-1).ToString() +".tre";
            psi.Arguments = paramsy;
            psi.CreateNoWindow = true;
            psi.RedirectStandardOutput = true;
            psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            psi.UseShellExecute = false;
            System.Diagnostics.Process listFiles;
            listFiles = System.Diagnostics.Process.Start(psi);
            System.IO.StreamReader myOutput = listFiles.StandardOutput;
            listFiles.WaitForExit();
            if (listFiles.HasExited)
            {
                string output = myOutput.ReadToEnd();
                //this.processResults.Text = output;
                File.Delete("drzewko.phy");
            }
        }

        private void simulationTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (simulationTypeComboBox.SelectedIndex == 0)
            {
                _simulationType = SimulationType.ExisitingTree;
                wczytajStruktureButton.Enabled = true;
            }
            else
            {
                _simulationType = SimulationType.StartSequence;
                wczytajStruktureButton.Enabled = false;
                treeFileLabel.Text = "brak";
            }
        }

        private void OpenFileButton_Click(object sender, EventArgs e)
        {
            var dialog = new OpenFileDialog();
            //TODO: umożliwić wczytywanie tylko poprawnych formatów dla określonego typu ewolucji
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                _path = dialog.FileName;
                SetPathLabel();
                showTreeButton.Enabled = false;
            }
        }

        private void SetPathLabel()
        {
            if (_path.Length < 100)
                filePathLabel.Text = _path;
            else
            {
                // Skrócenie długiej ścieżki, aby mieściła się w oknie
                int first = _path.IndexOf('\\') + 1;
                int last = _path.LastIndexOf('\\');
                filePathLabel.Text = _path.Substring(0, first) + "..." + _path.Substring(last);
            }
        }

		private void SetTreePathLabel(string file_name)
        {
            if (file_name.Length < 80)
                treeFileLabel.Text = file_name;
            else
            {
                // Skrócenie długiej ścieżki, aby mieściła się w oknie
                int first = file_name.IndexOf('\\') + 1;
                int last = file_name.LastIndexOf('\\');
                treeFileLabel.Text = file_name.Substring(0, first) + "..." + file_name.Substring(last);
            }
        }
        private void zapiszButton_Click(object sender, EventArgs e)
        {
            WriterReader zapisz = new WriterReader();
            zapisz.Save(_root);
        }
		
		private void button1_Click(object sender, EventArgs e)
        {
            WriterReader zapisz = new WriterReader();
            zapisz.SaveStructure(_root);
        }

        private void wczytajStruktureButton_Click(object sender, EventArgs e)
        {
            WriterReader otworz = new WriterReader();
            OpenFileDialog sfo = new OpenFileDialog();
            sfo.DefaultExt = ".str"; // Default file extension
            sfo.Filter = "Tree documents (.str)|*.str"; // Filter files by extension

            if (sfo.ShowDialog() == DialogResult.OK)
            {
                _root = otworz.ReadStructure(sfo.FileName);
                SetTreePathLabel(sfo.FileName);
            }
        }
    }
}